﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Xml.Linq;
using CoolCode.Data.Linq;
using CoolCode.Linq.Expressions;

namespace CoolCode.Data.Xml
{
    class ConditionBuilder : ExpressionVisitor
    {
        public Expression Result { get; private set; }

        private ParameterExpression c = Expression.Parameter(typeof(XElement), "c");

        private Type originalType;

        public ConditionBuilder(Expression exp)
        {
            Result = this.Visit(exp);
        }

        //protected override Expression VisitParameter(ParameterExpression p)
        //{
        //    return base.VisitParameter(p);
        //}

        //protected override Expression Visit(Expression exp)
        //{
        //    //var t = exp.Type;
        //    return base.Visit(exp);
        //}

        /// <summary>
        /// Updated in Mar 16, 2009 Add a condition : m.Expression.Type != originalType
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        protected override Expression VisitMemberAccess(MemberExpression m)
        {

            if (m.Expression == null || m.NodeType == ExpressionType.Constant || m.Expression.Type != originalType)
            {
                return base.VisitMemberAccess(m);
            }
           
            var method = typeof(XElement).GetMethod("Element", new Type[] { typeof(XName) });
            Expression cond = Expression.Constant(true);
            var mcall = Expression.Call(c, method,
                    new Expression[] { Expression.Constant((XName)m.Member.Name, typeof(XName)) }             // arguments  
                   );
            //var prop = Expression.Property(mcall, "Value");
            var member = Expression.Convert(mcall, m.Type);
            return member;
        }

        protected override Expression VisitLambda(LambdaExpression lambda)
        {
            originalType = lambda.Parameters[0].Type;
            // ParameterExpression c = Expression.Parameter(typeof(XElement), "c");
            var vlambda = Expression.Lambda<Func<XElement, bool>>(
                 lambda.Body,
                 new ParameterExpression[] { c }
             );
            return base.VisitLambda(vlambda);
        }
    }
}
